/**
 * 金额格式化
 * 千分位转为两位小数点金额，两位小数点金额转为千分位金额
 * 金额的加减乘除
 * 金额的四舍五入
 */
const amountFormat = {
	formatNum(str) { //采用循环的方式实现。
		var newStr = "";
		var count = 0;

		if (str.indexOf(".") == -1) {
			for (var i = str.length - 1; i >= 0; i--) {
				if (count % 3 == 0 && count != 0) {
					newStr = str.charAt(i) + "," + newStr;
				} else {
					newStr = str.charAt(i) + newStr;
				}
				count++;
			}
			str = newStr + ".00"; //自动补小数点后两位
			console.log(str)
			return str;
		} else {
			for (var i = str.indexOf(".") - 1; i >= 0; i--) {
				if (count % 3 == 0 && count != 0) {
					newStr = str.charAt(i) + "," + newStr; //碰到3的倍数则加上“,”号
				} else {
					newStr = str.charAt(i) + newStr; //逐个字符相接起来
				}
				count++;
			}
			str = newStr + (str + "00").substr((str + "00").indexOf("."), 3);
			console.log(str)
			return str;
		}
	},
	amountFormatThousandth(amount) {
		var stramount = amount + "";
		return this.formatNum(stramount);
		//todo 采用正则表达式方式实现  有bug，会在千分位中丢掉部分数字。
		// //千分位转为两位小数点金额，两位小数点金额转为千分位金额
		// var regex = /(\d)(?=(\d\d\d)+(?!\d))/g;

		// if (amount.indexOf(".") == -1) {
		// 	amount = amount.replace(regex, ',') + '.00';
		// 	return amount;
		// } else {
		// 	var newStr = amount.split('.');
		// 	var str_2 = newStr[0].replace(regex, ',');

		// 	if (newStr[1].length <= 1) {
		// 		//小数点后只有一位时
		// 		str_2 = str_2 + '.' + newStr[1] + '0';
		// 		console.log(str_2)
		// 		return amount;

		// 	} else if (newStr[1].length > 1) {
		// 		//小数点后两位以上时
		// 		var decimals = newStr[1].substr(0, 2);
		// 		var srt_3 = str_2 + '.' + decimals;
		// 		console.log(srt_3)
		// 		return amount;
		// 	}
		// }
	},
	thousandthFormatamount(thousandth) {
		//两位小数点金额转为千分位金额
		if ((thousandth + "").trim() == "") {
			return "";
		}
		thousandth = thousandth.replace(/,/gi, '');
		return thousandth;
	},
	// 核心方法，实现加减乘除运算，确保不丢失精度
	// * 思路：把小数放大为整数（乘），进行算术运算，再缩小为小数（除）
	amountAdd(amount, targetAmount) {
		//金额相加
		// var num1 = 1.528;
		// num2 = 1.2;
		var r1, r2, m, a;
		try {
			r1 = amount.toString().split('.')[1].length;
		} catch (e) {
			r1 = 0;
		}
		try {
			r2 = targetAmount.toString().split(".")[1].length;
		} catch (e) {
			r2 = 0;
		}
		m = Math.pow(10, Math.max(r1, r2));
		a = Math.round(amount * m + targetAmount * m) / m
		console.log(a);
		return a;
	},
	amountSubtract(amount, targetAmount) {
		//金额相减
		var r1, r2, m, c;
		try {
			r1 = amount.toString().split(".")[1].length;
		} catch (e) {
			r1 = 0;
		}
		try {
			r2 = targetAmount.toString().split(".")[1].length;
		} catch (e) {
			r2 = 0;
		}
		c = Math.abs(r1 - r2);
		m = Math.pow(10, Math.max(r1, r2));
		if (c > 0) {
			var cm = Math.pow(10, c);
			if (r1 > r2) {
				amount = Number(amount.toString().replace(".", ""));
				targetAmount = Number(targetAmount.toString().replace(".", "")) * cm;
			} else {
				amount = Number(amount.toString().replace(".", "")) * cm;
				targetAmount = Number(targetAmount.toString().replace(".", ""));
			}
		} else {
			amount = Number(amount.toString().replace(".", ""));
			targetAmount = Number(targetAmount.toString().replace(".", ""));
		}
		return (amount - targetAmount) / m;
	},
	amountMultiply(amount, targetAmount) {
		//金额相乘
		return this.operation(amount, targetAmount, 10, 'multiply')
	},
	amountDivided(amount, targetAmount) {
		//金额相除
		return this.operation(amount, targetAmount, 10, 'divide')
	},
	amountRounding(number, decimals, dec_point, thousands_sep, roundtag) {
		//金额四舍五入
		//这些代码基本能很好的运行。不过关系到经济利益的时候，还要考虑舍去或者舍入几厘。大家懂的，每个用户几厘钱可能带来巨大的经济收益。
		// 就比如说收手续费，如果一笔手续费计算出来是 3.4521 元，精确到分一般都会收 3.46 元。当然如果是付出去，那可能就是直接舍去了，
		// 一般会计算为 3.45 元。
		/*
		 * 参数说明：
		 * number：要格式化的数字
		 * decimals：保留几位小数
		 * dec_point：小数点符号
		 * thousands_sep：千分位符号
		 * roundtag:舍入参数，默认 "ceil" 向上取,"floor"向下取,"round" 四舍五入
		 * */
		number = (number + '').replace(/[^0-9+-Ee.]/g, '');
		roundtag = roundtag || "ceil"; //"ceil","floor","round"
		var n = !isFinite(+number) ? 0 : +number,
			prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
			sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
			dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
			s = '',
			toFixedFix = function(n, prec) {

				var k = Math.pow(10, prec);
				console.log();

				return '' + parseFloat(Math[roundtag](parseFloat((n * k).toFixed(prec * 2))).toFixed(prec * 2)) / k;
			};
		s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
		var re = /(-?\d+)(\d{3})/;
		while (re.test(s[0])) {
			s[0] = s[0].replace(re, "$1" + sep + "$2");
		}

		if ((s[1] || '').length < prec) {
			s[1] = s[1] || '';
			s[1] += new Array(prec - s[1].length + 1).join('0');
		}
		return s.join(dec);
	},

	/*
	 * 核心方法，实现加减乘除运算，确保不丢失精度
	 * 思路：把小数放大为整数（乘），进行算术运算，再缩小为小数（除）
	 *
	 * @param a {number} 运算数1
	 * @param b {number} 运算数2
	 * @param digits {number} 精度，保留的小数点数，比如 2, 即保留为两位小数
	 * @param op {string} 运算类型，有加减乘除（add/subtract/multiply/divide）
	 *
	 */
	operation(a, b, digits, op) {
		var o1 = this.toInteger(a)
		var o2 = this.toInteger(b)
		var n1 = o1.num
		var n2 = o2.num
		var t1 = o1.times
		var t2 = o2.times
		var max = t1 > t2 ? t1 : t2
		var result = null
		switch (op) {
			case 'add':
				if (t1 === t2) { // 两个小数位数相同
					result = n1 + n2
				} else if (t1 > t2) { // o1 小数位 大于 o2
					result = n1 + n2 * (t1 / t2)
				} else { // o1 小数位 小于 o2
					result = n1 * (t2 / t1) + n2
				}
				return result / max
			case 'subtract':
				if (t1 === t2) {
					result = n1 - n2
				} else if (t1 > t2) {
					result = n1 - n2 * (t1 / t2)
				} else {
					result = n1 * (t2 / t1) - n2
				}
				return result / max
			case 'multiply':
				result = (n1 * n2) / (t1 * t2)
				return result
			case 'divide':
				result = (n1 / n2) * (t2 / t1)
				return result
		}
	},
	/*
	 * 判断obj是否为一个整数
	 */
	isInteger(obj) {
		return Math.floor(obj) === obj
	},

	/*
	 * 将一个浮点数转成整数，返回整数和倍数。如 3.14 >> 314，倍数是 100
	 * @param floatNum {number} 小数
	 * @return {object}
	 *   {times:100, num: 314}
	 */
	toInteger(floatNum) {
		var ret = {
			times: 1,
			num: 0
		}
		if (this.isInteger(floatNum)) {
			ret.num = floatNum
			return ret
		}
		var strfi = floatNum + ''
		var dotPos = strfi.indexOf('.')
		var len = strfi.substr(dotPos + 1).length
		var times = Math.pow(10, len)
		var intNum = parseInt(floatNum * times + 0.5, 10)
		ret.times = times
		ret.num = intNum
		return ret
	},

}

export default {
	amountFormatThousandth: amountFormat.amountFormatThousandth,
	thousandthFormatamount: amountFormat.thousandthFormatamount,
	amountAdd: amountFormat.amountAdd,
	amountSubtract: amountFormat.amountSubtract,
	amountMultiply: amountFormat.amountMultiply,
	amountDivided: amountFormat.amountDivided,
	amountRounding: amountFormat.amountRounding,
	formatNum: amountFormat.formatNum,
	operation: amountFormat.operation,
	isInteger: amountFormat.isInteger,
	toInteger: amountFormat.toInteger,
}
//关于精度损失方面的说明
//JS: 0.1＋0.2会等于0.30000000004
// 注：下面为早期学习记录未注明原作者，找到时补上。

// JavaScript的number类型按照ECMA的JavaScript标准，它的Number类型就是IEEE 754的双精度数值，相当于java的double类型。IEEE 754标准《二进制浮点数算法》（www.ieee.org）就是一个对实数进行计算机编码的标准。因此精度问题不止JS这门语言独有。

// 无论是用纸张记录数值，还是用计算机记录数值，都必须用某种编码方案来表达数值。必须理解的是，用编码表达的数值不是数值本身，而只是数值的一种人类或计算机可理解的描述。任何编码方案都有其局限，要么是表达范围（精度）方面的限制，要么是其他复杂性方面的制约。

// 绝对完美的数值编码方案是不存在的，为了处理方便，这个标准引入了大量的折衷和妥协，建立在这种表达方式上的算法（例如除法运算）也一样。由于数值表达方式存在“缺陷”，运算结果不可避免地堆聚起越来越多的误差。

// 按IEEE 754格式保存的浮点数精度相当于带有15、16或17位小数位数的十进制小数，由于存在二进制和十进制的转换问题，具体的位数会发生变化。要获得最高的转换精度，必须指定17位的小数——此时可以相信前15位的精度。

// 在JavaScript中输出下面这些数值（注意不能作为字符串输出）：0.1000000000000000000000000001（28位小数）、0.100000000000000000000000001（27位小数）、0.1000000000000000000000000456（28位小数）、0.09999999999999999999999（23位小数），显示出来的结果都是数值0.1。又如，如果输出1/3的有理数表达式，结果是0.3333333333333333。

// 因此JavaScript小数在做四则运算时，精度会丢失。
// 当然也有一些方法可以来保证一定的精度：http://jiangzhengjun.iteye.com/blog/4...
// 也有人总结了一些原则：

// 原则
// ■ 大多数Web页面不需要小数 避免使用小数，尽量设法使用整数。确保数组的索引都是整数。按分（而不是元）计算金额。百分比放大100倍计算以避免出现小数。尽可能不用除法（/）和模（%）运算，因为大多数情况下它们直接导致出现浮点数。如果必须使用除法，立即用Math.round方法回归整数运算。

// ■ 如果必须使用浮点数，则尽可能引入冗余小数位——即在程序要求的运算精度之外，再增加小数位 如果程序需要5位数字的小数精度，则在运算中至少保留6位的小数，8位更好。冗余位越多，累计误差的影响越小。

// ■ 避免在同一个表达式中使用相差太大或太小的数值 对两个非常接近的数值执行减法或比较操作很容易出错。将很小的数值和很大数值相加无异于浪费时间，小的数值很可能被当作0。不过，很小的数值乘以很大的数值一般不会出现问题，例如2 * 12345678会得到正确的结果24691356。但是，0.1 - 0.09的结果是0.010000000000000009。

// ■ 用isFinite()和isNaN()检查运算结果 通过表单提交任何数值运算结果之前，一定要先检查数据的合法性。

// ■ 慎用数值运算 程序涉及的数值运算越少，引入误差的可能就越小。视浮点数为贵客，不可任意驱使。
